﻿using System;

namespace AssemblerCompiler
{
    internal static class ZeroOperandsTranslator
    {
        public static Byte[] ParseNOP(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                      ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = 0x90;
            return code;
        }

        public static Byte[] ParsePUSH(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                       ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = ((9 << 4) | 12);
            return code;
        }

        public static Byte[] ParsePOP(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                      ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = ((9 << 4) | 13);
            return code;
        }

        public static Byte[] ParseRET(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                      ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = ((12 << 4) | 3);
            return code;
        }

        public static Byte[] ParseCBW(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                      ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = ((9 << 4) | 8);
            return code;
        }

        public static Byte[] ParseCWD(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                      ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = ((9 << 4) | 9);
            return code;
        }

        public static Byte[] ParsePUSHF(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                        ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = ((9 << 4) | 12);
            return code;
        }

        public static Byte[] ParsePOPF(ref bool needWriteMemory, ref int byteIndToWriteMemory, ref bool needWriteD8,
                                       ref int byteToWriteD8, ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code;
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[1];
            code[0] = ((9 << 4) | 13);
            return code;
        }
    }

    internal static class OneOperandTranslator
    {
        private static int regSet = (1 << 16) - 1;

        private static int regSetByte = (1 | 4 | 16 | 64 | 256 | 1024 | 4096 | 16384);

        private static int sregSet = ((1 << 6) - 1) << 16;

        public static Byte[] ParseLOOP(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                       ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                       ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of LOOP command!");
            }

            code = new Byte[2];
            code[0] = (14 << 4) | 2;
            needWriteD8 = true;
            byteToWriteD8 = 1;

            return code;
        }

        public static Byte[] ParseLOOPE(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                        ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                        ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of LOOPE command!");
            }

            code = new Byte[2];
            code[0] = (14 << 4) | 1;
            needWriteD8 = true;
            byteToWriteD8 = 1;

            return code;
        }

        public static Byte[] ParseJE(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                     ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                     ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of JE command!");
            }

            code = new Byte[2];
            code[0] = (7 << 4) | 4;
            needWriteD8 = true;
            byteToWriteD8 = 1;

            return code;
        }

        public static Byte[] ParseJG(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                     ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                     ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of JG command!");
            }

            code = new Byte[2];
            code[0] = (7 << 4) | 15;
            needWriteD8 = true;
            byteToWriteD8 = 1;

            return code;
        }

        public static Byte[] ParseJL(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                     ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                     ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of JL command!");
            }

            code = new Byte[2];
            code[0] = (7 << 4) | 12;
            needWriteD8 = true;
            byteToWriteD8 = 1;

            return code;
        }

        public static Byte[] ParseJNE(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of JNE command!");
            }

            code = new Byte[2];
            code[0] = (7 << 4) | 5;
            needWriteD8 = true;
            byteToWriteD8 = 1;

            return code;
        }

        public static Byte[] ParseJMP(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of JNE command!");
            }

            code = new Byte[2];
            code[0] = (14 << 4) | 11;
            needWriteD8 = true;
            byteToWriteD8 = 1;

            return code;
        }

        public static Byte[] ParseCALL(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                       ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                       ref int byteToWriteD16)
        {
            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;

            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Pointer)
            {
                throw new Exception("Error in operand of JNE command!");
            }

            code = new Byte[3];
            code[0] = (14 << 4) | 8;
            needWriteD16 = true;
            byteToWriteD16 = 1;

            return code;
        }

        public static Byte[] ParseINT(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }

            if (op1.Size_ == Operand.Size.Word)
            {
                throw new Exception("Error in operand!");
            }

            if (op1.IM > 255)
            {
                throw new Exception("Error in operand!");
            }

            code = new Byte[2];
            code[0] = ((12 << 4) | 13);
            code[1] = (Byte) op1.IM;

            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;
        }

        public static Byte[] ParsePUSH(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                       ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                       ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT == Operand.AddressingType.Immediate) // PUSH IM
            {
                code = new Byte[3];

                code[0] = ((6 << 4) | 8);
                code[1] = (Byte) (op1.IM & 255);
                code[2] = (Byte) (op1.IM >> 8);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.Register && ((int) op1.R & regSet) != 0) // PUSH R
            {
                code = new Byte[1];
                code[0] = ((5 << 4));
                code[0] |= Operand.getRegBits(op1.R);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.Register &&
                (op1.R == Operand.Register.ES || op1.R == Operand.Register.CS || op1.R == Operand.Register.SS ||
                 op1.R == Operand.Register.DS)) // PUSH ES, CS, SS, DS
            {
                code = new Byte[1];
                code[0] = (Byte) ((Operand.getRegBits(op1.R) << 3) | 6);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.Register &&
                (op1.R == Operand.Register.FS || op1.R == Operand.Register.GS)) // PUSH FS, GS
            {
                code = new Byte[2];
                code[0] = 15;
                code[1] = (Byte) ((8 << 4) | (Operand.getRegBits(op1.R) << 3));

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.Register)
            {
                throw new Exception("Error in operand!");
            }

            // PUSH M

            if (op1.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];

                code[0] = ((15 << 4) | 15);
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= (6 << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            code = new Byte[4];

            code[0] = ((15 << 4) | 15);
            code[1] = Operand.GetModRMByte(op1);
            code[1] |= (6 << 3);

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;
        }

        public static Byte[] ParsePOP(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }

            if (op1.AT == Operand.AddressingType.Register && ((int) op1.R & regSet) != 0) // POP R
            {
                code = new Byte[1];
                code[0] = (Byte) ((5 << 4) | 8 | Operand.getRegBits(op1.R));

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.Register &&
                (op1.R == Operand.Register.ES || op1.R == Operand.Register.CS || op1.R == Operand.Register.SS ||
                 op1.R == Operand.Register.DS)) // POP ES, CS, SS, DS
            {
                code = new Byte[1];
                code[0] = (Byte) ((Operand.getRegBits(op1.R) << 3) | 7);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.Register &&
                (op1.R == Operand.Register.FS || op1.R == Operand.Register.GS)) // POP FS, GS
            {
                code = new Byte[2];
                code[0] = 15;
                code[1] = (Byte) ((8 << 4) | (Operand.getRegBits(op1.R) << 3) | 1);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.Register)
            {
                throw new Exception("Error in operand!");
            }

            // POP M

            if (op1.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];

                code[0] = ((8 << 4) | 15);
                code[1] = Operand.GetModRMByte(op1);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            code = new Byte[4];

            code[0] = ((8 << 4) | 15);
            code[1] = Operand.GetModRMByte(op1);

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;
        }

        public static Byte[] ParseRET(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }

            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;
            code = new Byte[3];
            code[0] = ((12 << 4) | 2);
            code[1] = (Byte) (op1.IM & 255);
            code[2] = (Byte) (op1.IM >> 8);

            return code;
        }

        public static Byte[] ParseNOT(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }

            if (op1.AT == Operand.AddressingType.Register)
            {
                code = new Byte[2];
                code[0] = ((15 << 4) | 6);
                if (Operand.getSize(op1.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }
                code[1] = (Byte) (Operand.GetModRMByte(op1) | 16);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op1.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];
                code[0] = ((15 << 4) | 7);
                code[1] = (Byte) (Operand.GetModRMByte(op1) | 16);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            code = new Byte[4];
            code[0] = ((15 << 4) | 7);
            code[1] = (Byte) (Operand.GetModRMByte(op1) | 16);

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;
        }

        public static Byte[] ParseINC(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            Byte T = 0;
            Byte t = ((4 << 4));

            if (op1.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }

            #region INC R

            if (op1.AT == Operand.AddressingType.Register)
            {
                if (((int) op1.R & regSet) == 0)
                {
                    throw new Exception("Error in operand!");
                }

                code = new Byte[1];

                code[0] = (Byte) (t | Operand.getRegBits(op1.R));

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region INC M

            if (op1.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];

                code[0] = ((15 << 4) | 15);
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            code = new Byte[4];

            code[0] = ((15 << 4) | 15);
            code[1] = Operand.GetModRMByte(op1);
            code[1] |= T;

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;

            #endregion
        }

        public static Byte[] ParseDEC(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            Byte T = 8;
            Byte t = ((4 << 4) | 8);

            if (op1.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }

            #region DEC R

            if (op1.AT == Operand.AddressingType.Register)
            {
                if (((int) op1.R & regSet) == 0)
                {
                    throw new Exception("Error in operand!");
                }

                code = new Byte[1];

                code[0] = (Byte) (t | Operand.getRegBits(op1.R));

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region DEC M

            if (op1.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];

                code[0] = ((15 << 4) | 15);
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            code = new Byte[4];

            code[0] = ((15 << 4) | 15);
            code[1] = Operand.GetModRMByte(op1);
            code[1] |= T;

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;

            #endregion
        }

        public static Byte[] ParseIDIV(Operand op1, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                       ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                       ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operands!");
            }

            #region IDIV R

            if (op1.AT == Operand.AddressingType.Register)
            {
                if (((int) op1.R & 255) == 0)
                {
                    throw new Exception("Error in operands!");
                }

                code = new Byte[2];

                code[0] = ((15 << 4) | 6);

                if (Operand.getSize(op1.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }

                code[1] = Operand.GetModRMByte(op1);
                code[1] |= (7 << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region IDIV M

            if (op1.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];

                code[0] = ((15 << 4) | 7);

                code[1] = Operand.GetModRMByte(op1);
                code[1] |= (7 << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region IDIV M

            code = new Byte[4];

            code[0] = ((15 << 4) | 7);

            code[1] = Operand.GetModRMByte(op1);
            code[1] |= (7 << 3);

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;

            #endregion
        }
    }

    internal static class TwoOperandsTranslator
    {
        private static int regSet = (1 << 16) - 1;

        private static int regSetByte = (1 | 4 | 16 | 64 | 256 | 1024 | 4096 | 16384);

        private static int sregSet = ((1 << 6) - 1) << 16;

        private static Byte[] Parse_ADD_SUB_AND_OR_XOR_CMP(Byte T1, Byte T2, Operand op1, Operand op2,
                                                           ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                                           ref bool needWriteD8, ref int byteToWriteD8,
                                                           ref bool needWriteD16, ref int byteToWriteD16)
        {
            Byte[] code = null;

            #region ADD_SUB_AND_OR_XOR_CMP R/M, IM

            if (op2.AT == Operand.AddressingType.Immediate) // ..., IM
            {
                Operand.Size sz;

                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operand!");
                }

                #region ADD_SUB_AND_OR_XOR_CMP R, IM

                if (op1.AT == Operand.AddressingType.Register) // SUB R, IM
                {
                    if (op2.Size_ != Operand.Size.Undefined && op2.Size_ != Operand.getSize(op1.R))
                    {
                        throw new Exception("Operands have different sizes!");
                    }

                    if (Operand.getSize(op1.R) == Operand.Size.Byte && op2.Size_ == Operand.Size.Undefined &&
                        op2.IM > 255)
                    {
                        throw new Exception("Operands have different sizes!");
                    }

                    sz = Operand.getSize(op1.R);

                    if (sz == Operand.Size.Byte)
                    {
                        code = new Byte[3];
                        code[0] = ((8 << 4));
                        code[1] = Operand.GetModRMByte(op1);
                        code[1] |= T2;
                        code[2] = (Byte) op2.IM;
                    }

                    if (sz == Operand.Size.Word)
                    {
                        code = new Byte[4];
                        code[0] = ((8 << 4) | 1);
                        code[1] = Operand.GetModRMByte(op1);
                        code[1] |= T2;
                        code[2] = (Byte) (op2.IM & 255);
                        code[3] = (Byte) (op2.IM >> 8);
                    }

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                #endregion

                #region ADD_SUB_AND_OR_XOR_CMP M, IM

                if (op1.AT == Operand.AddressingType.Based) // SUB M, IM
                {
                    if (op2.Size_ == Operand.Size.Undefined)
                    {
                        throw new Exception("Error in operand, unknown size!");
                    }

                    sz = op2.Size_;

                    if (sz == Operand.Size.Byte)
                    {
                        code = new Byte[3];
                        code[0] = ((8 << 4));
                        code[1] = Operand.GetModRMByte(op1);
                        code[1] |= T2;
                        code[2] = (Byte) op2.IM;
                    }
                    else
                    {
                        code = new Byte[4];
                        code[0] = ((8 << 4) | 1);
                        code[1] = Operand.GetModRMByte(op1);
                        code[1] |= T2;
                        code[2] = (Byte) (op2.IM & 255);
                        code[3] = (Byte) (op2.IM >> 8);
                    }

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                #endregion

                #region ADD_SUB_AND_OR_XOR_CMP M, IM

                if (op2.Size_ == Operand.Size.Undefined)
                {
                    throw new Exception("Error in operand, unknown size!");
                }

                sz = op2.Size_;

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                if (sz == Operand.Size.Byte)
                {
                    code = new Byte[5];
                    code[0] = (8 << 4);
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T2;
                    code[4] = (Byte) op2.IM;
                }
                else
                {
                    code = new Byte[6];
                    code[0] = ((8 << 4) | 1);
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T2;
                    code[4] = (Byte) (op2.IM & 255);
                    code[5] = (Byte) (op2.IM >> 8);
                }

                return code;

                #endregion
            }

            #endregion

            #region ADD_SUB_AND_OR_XOR_CMP R, R

            if (op1.AT == Operand.AddressingType.Register && op2.AT == Operand.AddressingType.Register)
            {
                if (Operand.getSize(op1.R) != Operand.getSize(op2.R))
                {
                    throw new Exception("Operands have differenr sizes!");
                }

                if (((int) op1.R & regSet) == 0 || ((int) op2.R & regSet) == 0)
                {
                    throw new Exception("Not valid register type!");
                }

                Operand.Size sz = Operand.getSize(op1.R);

                code = new Byte[2];
                code[0] = T1;
                if (sz == Operand.Size.Word)
                {
                    code[0] |= 1;
                }

                code[1] = Operand.GetModRMByte(op1);
                code[1] |= (Byte) (Operand.getRegBits(op2.R) << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region ADD_SUB_AND_OR_XOR_CMP M, R

            if (op2.AT == Operand.AddressingType.Register)
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Based)
                {
                    code = new Byte[2];

                    code[0] = T1;
                    if (Operand.getSize(op2.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= (Byte) (Operand.getRegBits(op2.R) << 3);

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                code = new Byte[4];

                code[0] = T1;
                if (Operand.getSize(op2.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= (Byte) (Operand.getRegBits(op2.R) << 3);

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region ADD_SUB_AND_OR_XOR_CMP R, M

            if (op1.AT == Operand.AddressingType.Register)
            {
                if (op2.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Internal compiler error!");
                }

                if (op2.AT == Operand.AddressingType.Based)
                {
                    code = new Byte[2];

                    code[0] = (Byte) (T1 | 2);
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }
                    code[1] = Operand.GetModRMByte(op2);
                    code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                code = new Byte[4];

                code[0] = (Byte) (T1 | 2);
                if (Operand.getSize(op1.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }
                code[1] = Operand.GetModRMByte(op2);
                code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            throw new Exception("Error in operands!");
        }

        public static Byte[] ParseMOV(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operands!");
            }

            #region MOV R/M, IM

            if (op2.AT == Operand.AddressingType.Immediate) // MOV ..., IM
            {
                if (op1.AT == Operand.AddressingType.Register) // MOV R, IM
                {
                    if ((regSet & (int) op1.R) != 0)
                    {
                        if (op2.Size_ != Operand.Size.Undefined && op2.Size_ != Operand.getSize(op1.R))
                        {
                            throw new Exception("Operands of operator MOV have different size!");
                        }

                        Operand.Size sz = Operand.getSize(op1.R);
                        if (sz == Operand.Size.Byte)
                        {
                            code = new Byte[2];
                            if (op2.IM > 255)
                            {
                                throw new Exception("Operands of operator MOV have different size!");
                            }
                            code[1] = (Byte) op2.IM;
                        }
                        else
                        {
                            code = new Byte[3];
                            code[1] = (Byte) (op2.IM & 255);
                            code[2] = (Byte) (op2.IM >> 8);
                        }

                        code[0] = (11 << 4);
                        if (sz == Operand.Size.Word)
                        {
                            code[0] |= (1 << 3);
                        }
                        code[0] |= Operand.getRegBits(op1.R);

                        needWriteMemory = false;
                        byteIndToWriteMemory = -1;
                        needWriteD8 = false;
                        byteToWriteD8 = -1;
                        needWriteD16 = false;
                        byteToWriteD16 = -1;

                        return code;
                    }

                    throw new Exception("Invalid register in operator MOV!");
                }

                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Invalid operands in operator MOV!");
                }

                // MOV M, IM

                if (op2.Size_ == Operand.Size.Undefined)
                {
                    throw new Exception("Impossible to find out the size of operands!");
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit)
                {
                    if (op2.Size_ == Operand.Size.Byte)
                    {
                        code = new Byte[3];
                    }
                    if (op2.Size_ == Operand.Size.Word)
                    {
                        code = new Byte[4];
                    }
                    if (op2.Size_ == Operand.Size.Byte)
                    {
                        code[2] = (Byte) op2.IM;
                    }
                    if (op2.Size_ == Operand.Size.Word)
                    {
                        code[2] = (Byte) (op2.IM & 255);
                        code[3] = (Byte) (op2.IM >> 8);
                    }
                }
                else
                {
                    if (op2.Size_ == Operand.Size.Byte)
                    {
                        code = new Byte[5];
                    }
                    if (op2.Size_ == Operand.Size.Word)
                    {
                        code = new Byte[6];
                    }
                    if (op2.Size_ == Operand.Size.Byte)
                    {
                        code[4] = (Byte) op2.IM;
                    }
                    if (op2.Size_ == Operand.Size.Word)
                    {
                        code[4] = (Byte) (op2.IM & 255);
                        code[5] = (Byte) (op2.IM >> 8);
                    }
                }

                code[0] = (12 << 4) | 6;
                if (op2.Size_ == Operand.Size.Word)
                {
                    code[0] |= 1;
                }
                code[1] = Operand.GetModRMByte(op1);

                if (op1.AT == Operand.AddressingType.Pointer || op1.AT == Operand.AddressingType.PointerWithIndexing)
                {
                    needWriteMemory = true;
                    byteIndToWriteMemory = 2;
                }
                else
                {
                    if (op1.AT == Operand.AddressingType.Based)
                    {
                        code[2] = (Byte) (op1.Offset & 255);
                        code[3] = (Byte) (op1.Offset >> 8);
                    }
                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                }
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region MOV SR, R/M

            if (op1.AT == Operand.AddressingType.Register && ((int) op1.R & sregSet) != 0) // MOV SR, ...
            {
                if (op2.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Invalid operand!");
                }

                if (op2.AT == Operand.AddressingType.Register) // MOV SR, R
                {
                    if (((int) op2.R & regSet) == 0 || ((int) op2.R & regSetByte) != 1)
                    {
                        throw new Exception("Invalid operand!");
                    }

                    code = new Byte[2];
                    code[0] = ((8 << 4) | 14);
                    code[1] = (Byte) ((3 << 6) | (Operand.getSregBits(op1.R) << 3) | Operand.getRegBits(op2.R));

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;
                    return code;
                }

                // MOV SR, M

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                if (op1.AT == Operand.AddressingType.RegisterImplicit)
                {
                    code = new Byte[2];
                }
                else
                {
                    code = new Byte[4];
                }

                code[0] = ((8 << 4) | 14);
                code[1] = (Byte) (Operand.GetModRMByte(op2) | (Operand.getSregBits(op1.R) << 3));

                if (op1.AT == Operand.AddressingType.Based)
                {
                    code[2] = (Byte) (op1.Offset & 255);
                    code[3] = (Byte) (op1.Offset >> 8);
                }
                if (op1.AT == Operand.AddressingType.PointerWithIndexing || op1.AT == Operand.AddressingType.Pointer)
                {
                    needWriteMemory = true;
                    byteIndToWriteMemory = 2;
                }
                return code;
            }

            #endregion

            #region MOV R/M, SR

            if (op2.AT == Operand.AddressingType.Register && ((int) op2.R & sregSet) != 0) // MOV ..., S/R
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Invalid operand!");
                }

                if (op1.AT == Operand.AddressingType.Register) // MOV R, SR
                {
                    if (((int) op1.R & regSet) == 0 || ((int) op1.R & regSetByte) != 1)
                    {
                        throw new Exception("Invalid operand!");
                    }

                    code = new Byte[2];
                    code[0] = ((8 << 4) | 12);
                    code[1] = (Byte) ((3 << 6) | (Operand.getSregBits(op2.R) << 3) | Operand.getRegBits(op1.R));

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;
                    return code;
                }

                // MOV M, SR

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                if (op2.AT == Operand.AddressingType.RegisterImplicit)
                {
                    code = new Byte[2];
                }
                else
                {
                    code = new Byte[4];
                }

                code[0] = ((8 << 4) | 12);
                code[1] = (Byte) (Operand.GetModRMByte(op1) | (Operand.getSregBits(op2.R) << 3));

                if (op2.AT == Operand.AddressingType.Based)
                {
                    code[2] = (Byte) (op2.Offset & 255);
                    code[3] = (Byte) (op2.Offset >> 8);
                }
                if (op2.AT == Operand.AddressingType.PointerWithIndexing || op2.AT == Operand.AddressingType.Pointer)
                {
                    needWriteMemory = true;
                    byteIndToWriteMemory = 2;
                }
                return code;
            }

            #endregion

            #region MOV R, R/M

            if (op1.AT == Operand.AddressingType.Register) // MOV R, ...
            {
                if (op2.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Internal compiler error!");
                }

                if (op2.AT == Operand.AddressingType.Register) // MOV R, R
                {
                    if (((int) op2.R & regSet) == 0 || Operand.getSize(op1.R) != Operand.getSize(op2.R))
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[2];
                    code[0] = (8 << 4) | 10;
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op2);
                    code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;
                    return code;
                }

                // MOV R, M

                if (op2.AT == Operand.AddressingType.RegisterImplicit)
                {
                    code = new Byte[2];
                }
                else
                {
                    code = new Byte[4];
                }

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                code[0] = (8 << 4) | 10;
                if (Operand.getSize(op1.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }

                code[1] = Operand.GetModRMByte(op2);
                code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                if (op2.AT == Operand.AddressingType.Pointer || op2.AT == Operand.AddressingType.PointerWithIndexing)
                {
                    needWriteMemory = true;
                    byteIndToWriteMemory = 2;
                }

                if (op2.AT == Operand.AddressingType.Based)
                {
                    code[2] = (Byte) (op2.Offset & 255);
                    code[3] = (Byte) (op2.Offset >> 8);
                }

                return code;
            }

            #endregion

            #region MOV M, R

            // MOV M, R
            if (op2.AT != Operand.AddressingType.Register)
            {
                throw new Exception("Error in operands!");
            }

            // MOV M, R

            if (op1.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];
            }
            else
            {
                code = new Byte[4];
            }

            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            code[0] = (8 << 4) | 8;
            if (Operand.getSize(op2.R) == Operand.Size.Word)
            {
                code[0] |= 1;
            }

            code[1] = Operand.GetModRMByte(op1);
            code[1] |= (Byte) (Operand.getRegBits(op2.R) << 3);

            if (op1.AT == Operand.AddressingType.Pointer || op1.AT == Operand.AddressingType.PointerWithIndexing)
            {
                needWriteMemory = true;
                byteIndToWriteMemory = 2;
            }

            if (op1.AT == Operand.AddressingType.Based)
            {
                code[2] = (Byte) (op1.Offset & 255);
                code[3] = (Byte) (op1.Offset >> 8);
            }

            return code;

            #endregion
        }

        public static Byte[] ParseLEA(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Register)
            {
                throw new Exception("Error in operand!");
            }
            if (((int) op1.R & regSet) == 0 || Operand.getSize(op1.R) != Operand.Size.Word)
            {
                throw new Exception("Error in operand!");
            }
            if (op2.AT == Operand.AddressingType.Register || op2.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }

            needWriteMemory = false;
            byteIndToWriteMemory = -1;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            if (op2.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[2];
            }
            else
            {
                code = new Byte[4];
            }

            code[0] = ((8 << 4) | 13);
            code[1] = Operand.GetModRMByte(op2);
            code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

            if (op2.AT == Operand.AddressingType.Based)
            {
                code[2] = (Byte) (op2.Offset & 255);
                code[3] = (Byte) (op2.Offset >> 8);
            }
            if (op2.AT == Operand.AddressingType.Pointer || op2.AT == Operand.AddressingType.PointerWithIndexing)
            {
                needWriteMemory = true;
                byteIndToWriteMemory = 2;
            }

            return code;
        }

        public static Byte[] ParseADD(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            return Parse_ADD_SUB_AND_OR_XOR_CMP(0, 0, op1, op2, ref needWriteMemory, ref byteIndToWriteMemory,
                                                ref needWriteD8, ref byteToWriteD8, ref needWriteD16, ref byteToWriteD16);
        }

        public static Byte[] ParseSUB(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            return Parse_ADD_SUB_AND_OR_XOR_CMP(((2 << 4) | 8), (5 << 3), op1, op2, ref needWriteMemory,
                                                ref byteIndToWriteMemory, ref needWriteD8, ref byteToWriteD8,
                                                ref needWriteD16, ref byteToWriteD16);
        }

        public static Byte[] ParseAND(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            return Parse_ADD_SUB_AND_OR_XOR_CMP(((2 << 4)), (4 << 3), op1, op2, ref needWriteMemory,
                                                ref byteIndToWriteMemory, ref needWriteD8, ref byteToWriteD8,
                                                ref needWriteD16, ref byteToWriteD16);
        }

        public static Byte[] ParseOR(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                     ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                     ref int byteToWriteD16)
        {
            return Parse_ADD_SUB_AND_OR_XOR_CMP((8), (1 << 3), op1, op2, ref needWriteMemory, ref byteIndToWriteMemory,
                                                ref needWriteD8, ref byteToWriteD8, ref needWriteD16, ref byteToWriteD16);
        }

        public static Byte[] ParseXOR(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            return Parse_ADD_SUB_AND_OR_XOR_CMP(((3 << 4)), (6 << 3), op1, op2, ref needWriteMemory,
                                                ref byteIndToWriteMemory, ref needWriteD8, ref byteToWriteD8,
                                                ref needWriteD16, ref byteToWriteD16);
        }

        public static Byte[] ParseCMP(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            return Parse_ADD_SUB_AND_OR_XOR_CMP(((3 << 4) | 8), (7 << 3), op1, op2, ref needWriteMemory,
                                                ref byteIndToWriteMemory, ref needWriteD8, ref byteToWriteD8,
                                                ref needWriteD16, ref byteToWriteD16);
        }

        public static Byte[] ParseXCHG(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                       ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                       ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT == Operand.AddressingType.Immediate || op2.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operand!");
            }
            if (op1.AT != Operand.AddressingType.Register && op2.AT != Operand.AddressingType.Register)
            {
                throw new Exception("Error in operand!");
            }

            Operand.Size sz;

            if (op1.AT != Operand.AddressingType.Register)
            {
                Operand op = op1;
                op1 = op2;
                op2 = op;
            }

            if (op2.AT == Operand.AddressingType.Register) // XCHG R, R
            {
                if (Operand.getSize(op1.R) != Operand.getSize(op2.R))
                {
                    throw new Exception("Operands have different sizes!");
                }

                sz = Operand.getSize(op1.R);

                code = new Byte[2];

                code[0] = ((8 << 4) | 6);
                if (sz == Operand.Size.Word)
                {
                    code[0] |= 1;
                }

                code[1] = Operand.GetModRMByte(op2);
                code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            if (op2.AT == Operand.AddressingType.RegisterImplicit) // XCHG R, M
            {
                sz = Operand.getSize(op1.R);
                code = new Byte[2];

                code[0] = ((8 << 4) | 6);
                if (sz == Operand.Size.Word)
                {
                    code[0] |= 1;
                }

                code[1] = Operand.GetModRMByte(op2);
                code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            sz = Operand.getSize(op1.R);
            code = new Byte[4];

            code[0] = ((8 << 4) | 6);
            if (sz == Operand.Size.Word)
            {
                code[0] |= 1;
            }

            code[1] = Operand.GetModRMByte(op2);
            code[1] |= (Byte) (Operand.getRegBits(op1.R) << 3);

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;
        }

        public static Byte[] ParseTEST(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                       ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                       ref int byteToWriteD16)
        {
            Byte[] code = null;

            #region TEST R/M, R

            if (op2.AT == Operand.AddressingType.Register) // TEST ..., R
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // TEST R, R
                {
                    if (Operand.getSize(op1.R) != Operand.getSize(op2.R))
                    {
                        throw new Exception("Operands have different sizes!");
                    }

                    if (((int) op1.R & regSet) == 0 || ((int) op2.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[2];

                    code[0] = ((8 << 4) | 4);
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= (Byte) (Operand.getRegBits(op2.R) << 3);

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // TEST M, R
                {
                    if (((int) op2.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[2];

                    code[0] = ((8 << 4) | 4);
                    if (Operand.getSize(op2.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= (Byte) (Operand.getRegBits(op2.R) << 3);

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (((int) op2.R & regSet) == 0)
                {
                    throw new Exception("Error in operands!");
                }

                // TEST M, R

                code = new Byte[4];

                code[0] = ((8 << 4) | 4);
                if (Operand.getSize(op2.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= (Byte) (Operand.getRegBits(op2.R) << 3);

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region TEST R/M, IM

            if (op2.AT == Operand.AddressingType.Immediate) // TEST ..., IM
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // TEST R, IM
                {
                    if (op2.Size_ != Operand.Size.Undefined && Operand.getSize(op1.R) != op2.Size_)
                    {
                        throw new Exception("Operands have different sizes!");
                    }

                    if (((int) op1.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    if (Operand.getSize(op1.R) == Operand.Size.Byte)
                    {
                        if (op2.IM > 255)
                        {
                            throw new Exception("Operands have different sizes!");
                        }
                        code = new Byte[3];
                        code[0] = ((15 << 4) | 6);
                        code[1] = (Byte) (Operand.GetModRMByte(op1) | (3 << 3));
                        code[2] = (Byte) op2.IM;
                    }
                    else
                    {
                        code = new Byte[4];
                        code[0] = ((15 << 4) | 7);
                        code[1] = (Byte) (Operand.GetModRMByte(op1) | (3 << 3));
                        code[2] = (Byte) (op2.IM & 255);
                        code[3] = (Byte) (op2.IM >> 8);
                    }

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // TEST M, IM
                {
                    if (op2.Size_ == Operand.Size.Undefined)
                    {
                        throw new Exception("Unknown size of operands!");
                    }

                    if (op2.Size_ == Operand.Size.Byte)
                    {
                        code = new Byte[3];
                        code[0] = ((15 << 4) | 6);
                        code[1] = (Byte) (Operand.GetModRMByte(op1) | (3 << 3));
                        code[2] = (Byte) op2.IM;
                    }
                    else
                    {
                        code = new Byte[4];
                        code[0] = ((15 << 4) | 7);
                        code[1] = (Byte) (Operand.GetModRMByte(op1) | (3 << 3));
                        code[2] = (Byte) (op2.IM & 255);
                        code[3] = (Byte) (op2.IM >> 8);
                    }

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                // TEST M, IM

                if (op2.Size_ == Operand.Size.Undefined)
                {
                    throw new Exception("Unknown size of operands!");
                }

                if (op2.Size_ == Operand.Size.Byte)
                {
                    code = new Byte[5];
                    code[0] = ((15 << 4) | 6);
                    code[1] = (Byte) (Operand.GetModRMByte(op1) | (3 << 3));
                    code[4] = (Byte) op2.IM;
                }
                else
                {
                    code = new Byte[6];
                    code[0] = ((15 << 4) | 7);
                    code[1] = (Byte) (Operand.GetModRMByte(op1) | (3 << 3));
                    code[4] = (Byte) (op2.IM & 255);
                    code[5] = (Byte) (op2.IM >> 8);
                }

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            throw new Exception("Error in operands!");
        }

        public static Byte[] ParseSHL(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            Byte T = (4 << 3);

            #region SHL R/M, 1

            if (op2.AT == Operand.AddressingType.Immediate && op2.IM == 1)
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // SHL R, 1
                {
                    if (((int) op1.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[2];

                    code[0] = ((13 << 4));
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // SHL M, 1
                {
                    code = new Byte[2];

                    code[0] = ((13 << 4) | 1);
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                code = new Byte[4];

                code[0] = ((13 << 4) | 1);
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region SHL R/M, CL

            if (op2.AT == Operand.AddressingType.Register && op2.R == Operand.Register.CL)
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // SHL R, CL
                {
                    if (((int) op1.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[2];

                    code[0] = ((13 << 4) | 2);
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // SHL M, CL
                {
                    code = new Byte[2];

                    code[0] = ((13 << 4) | 3);
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                code = new Byte[4];

                code[0] = ((13 << 4) | 3);
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region SHL M/R, IM

            if (op2.AT == Operand.AddressingType.Immediate)
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // SHL R, IM
                {
                    if (((int) op1.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    if (op1.Size_ == Operand.Size.Word || (op1.Size_ == Operand.Size.Undefined && op1.IM > 255))
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[3];

                    code[0] = ((12 << 4));
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    code[2] = (Byte) op2.IM;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // SHL M, IM
                {
                    if (op1.Size_ == Operand.Size.Word || (op1.Size_ == Operand.Size.Undefined && op1.IM > 255))
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[3];

                    code[0] = ((12 << 4));
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    code[2] = (Byte) op2.IM;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.Size_ == Operand.Size.Word || (op1.Size_ == Operand.Size.Undefined && op1.IM > 255))
                {
                    throw new Exception("Error in operands!");
                }

                code = new Byte[5];

                code[0] = ((12 << 4));
                if (Operand.getSize(op1.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }

                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                code[4] = (Byte) op2.IM;

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            throw new Exception("Error in operands!");
        }

        public static Byte[] ParseSHR(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                      ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                      ref int byteToWriteD16)
        {
            Byte[] code = null;

            Byte T = (5 << 3);

            #region SHR R/M, 1

            if (op2.AT == Operand.AddressingType.Immediate && op2.IM == 1)
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // SHR R, 1
                {
                    if (((int) op1.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[2];

                    code[0] = ((13 << 4));
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // SHR M, 1
                {
                    code = new Byte[2];

                    code[0] = ((13 << 4) | 1);
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                code = new Byte[4];

                code[0] = ((13 << 4) | 1);
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region SHR R/M, CL

            if (op2.AT == Operand.AddressingType.Register && op2.R == Operand.Register.CL)
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // SHR R, CL
                {
                    if (((int) op1.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[2];

                    code[0] = ((13 << 4) | 2);
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // SHR M, CL
                {
                    code = new Byte[2];

                    code[0] = ((13 << 4) | 3);
                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                code = new Byte[4];

                code[0] = ((13 << 4) | 3);
                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region SHR M/R, IM

            if (op2.AT == Operand.AddressingType.Immediate)
            {
                if (op1.AT == Operand.AddressingType.Immediate)
                {
                    throw new Exception("Error in operands!");
                }

                if (op1.AT == Operand.AddressingType.Register) // SHR R, IM
                {
                    if (((int) op1.R & regSet) == 0)
                    {
                        throw new Exception("Error in operands!");
                    }

                    if (op1.Size_ == Operand.Size.Word || (op1.Size_ == Operand.Size.Undefined && op1.IM > 255))
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[3];

                    code[0] = ((12 << 4));
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    code[2] = (Byte) op2.IM;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.AT == Operand.AddressingType.RegisterImplicit) // SHR M, IM
                {
                    if (op1.Size_ == Operand.Size.Word || (op1.Size_ == Operand.Size.Undefined && op1.IM > 255))
                    {
                        throw new Exception("Error in operands!");
                    }

                    code = new Byte[3];

                    code[0] = ((12 << 4));
                    if (Operand.getSize(op1.R) == Operand.Size.Word)
                    {
                        code[0] |= 1;
                    }

                    code[1] = Operand.GetModRMByte(op1);
                    code[1] |= T;

                    code[2] = (Byte) op2.IM;

                    needWriteMemory = false;
                    byteIndToWriteMemory = -1;
                    needWriteD8 = false;
                    byteToWriteD8 = -1;
                    needWriteD16 = false;
                    byteToWriteD16 = -1;

                    return code;
                }

                if (op1.Size_ == Operand.Size.Word || (op1.Size_ == Operand.Size.Undefined && op1.IM > 255))
                {
                    throw new Exception("Error in operands!");
                }

                code = new Byte[5];

                code[0] = ((12 << 4));
                if (Operand.getSize(op1.R) == Operand.Size.Word)
                {
                    code[0] |= 1;
                }

                code[1] = Operand.GetModRMByte(op1);
                code[1] |= T;

                code[4] = (Byte) op2.IM;

                needWriteMemory = true;
                byteIndToWriteMemory = 2;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            throw new Exception("Error in operands!");
        }

        public static Byte[] ParseIMUL(Operand op1, Operand op2, ref bool needWriteMemory, ref int byteIndToWriteMemory,
                                       ref bool needWriteD8, ref int byteToWriteD8, ref bool needWriteD16,
                                       ref int byteToWriteD16)
        {
            Byte[] code = null;

            if (op1.AT != Operand.AddressingType.Register)
            {
                throw new Exception("Error in operands!");
            }

            if (((int) op1.R & 255) == 0)
            {
                throw new Exception("Error in operands!");
            }

            if (Operand.getSize(op1.R) == Operand.Size.Byte)
            {
                throw new Exception("Error in operand! Registers must be 16-bit sized!");
            }

            if (op2.AT == Operand.AddressingType.Immediate)
            {
                throw new Exception("Error in operands!");
            }

            #region IMUL R, R

            if (op2.AT == Operand.AddressingType.Register)
            {
                if (((int) op2.R & 255) == 0)
                {
                    throw new Exception("Error in operands!");
                }

                if (Operand.getSize(op1.R) != Operand.getSize(op2.R))
                {
                    throw new Exception("Error in operands!");
                }

                code = new Byte[3];

                code[0] = 15;
                code[1] = ((10 << 4) | 15);
                code[2] = Operand.GetModRMByte(op2);
                code[2] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region IMUL R, M

            if (op2.AT == Operand.AddressingType.RegisterImplicit)
            {
                code = new Byte[3];

                code[0] = 15;
                code[1] = ((10 << 4) | 15);
                code[2] = Operand.GetModRMByte(op2);
                code[2] |= (Byte) (Operand.getRegBits(op1.R) << 3);

                needWriteMemory = false;
                byteIndToWriteMemory = -1;
                needWriteD8 = false;
                byteToWriteD8 = -1;
                needWriteD16 = false;
                byteToWriteD16 = -1;

                return code;
            }

            #endregion

            #region IMUL R, M

            code = new Byte[5];

            code[0] = 15;
            code[1] = ((10 << 4) | 15);
            code[2] = Operand.GetModRMByte(op2);
            code[2] |= (Byte) (Operand.getRegBits(op1.R) << 3);

            needWriteMemory = true;
            byteIndToWriteMemory = 2;
            needWriteD8 = false;
            byteToWriteD8 = -1;
            needWriteD16 = false;
            byteToWriteD16 = -1;

            return code;

            #endregion
        }
    }
}